//
//  control.m
//  jskick
//
//  Created by Andrew Barry on 14/02/09.
//  Copyright 2009 Barry Computer Services. All rights reserved.
//

#import "control.h"
#import "NSRadioButtonICM.h"
#import "WrappedJsval.h"
#import "ActionBridge.h"
#import "CanvasView.h"
#import "TableView.h"
#import "BrowserView.h"
#import "WebKit/WebView.h"
#import "WebKit/WebFrame.h"
#import "FlippedView.h"

int gInAnimation;

jsvalue cocoaViewFrameGetter(jscontext *cx, jsvalue obj, int sel) {
	NSView *view = idFromObject(cx, obj);
	NSRect frame = [view frame];
	double v = 0;
	switch (sel) {
		case 0:
			v = frame.origin.x;
			break;
		case 1:
			v = frame.origin.y;
			break;
		case 2:
			v = frame.size.width;
			break;
		case 3:
			v = frame.size.height;
			break;
	}
	return jsnum(cx, v);
}

void cocoaViewFrameSetter(jscontext *cx, jsvalue obj, jsvalue val, int sel) {
	NSView *view = idFromObject(cx, obj);
	NSRect frame = [view frame];
	double v = jsasnum(cx, val);
	switch (sel) {
		case 0:
			frame.origin.x = v;
			break;
		case 1:
			frame.origin.y = v;
			break;
		case 2:
			frame.size.width = v;
			break;
		case 3:
			frame.size.height = v;
			break;
	}
	[view setFrame:frame];
}

jsvalue cocoaLeftGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	return cocoaViewFrameGetter(cx, obj, 0);
}

jsvalue cocoaTopGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	return cocoaViewFrameGetter(cx, obj, 1);
}

jsvalue cocoaWidthGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	return cocoaViewFrameGetter(cx, obj, 2);
}

jsvalue cocoaHeightGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	return cocoaViewFrameGetter(cx, obj, 3);
}

jsvalue cocoaLeftSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	cocoaViewFrameSetter(cx, obj, argv[0], 0);
	return JSVAL_VOID;
}

jsvalue cocoaTopSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	cocoaViewFrameSetter(cx, obj, argv[0], 1);
	return JSVAL_VOID;
}

jsvalue cocoaWidthSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	cocoaViewFrameSetter(cx, obj, argv[0], 2);
	return JSVAL_VOID;
}

jsvalue cocoaHeightSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	cocoaViewFrameSetter(cx, obj, argv[0], 3);
	return JSVAL_VOID;
}

jsvalue cocoaVisibleGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSView *view = idFromObject(cx, obj);
	return BOOLEAN_TO_JSVAL(![view isHidden]);
}

jsvalue cocoaAlphaGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSView *view = idFromObject(cx, obj);
	
	return jsnum(cx, [view alphaValue]);
}

jsvalue controlEnabledGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSControl *view = idFromObject(cx, obj);
	return BOOLEAN_TO_JSVAL([view isEnabled]);
}

jsvalue cocoaVisibleSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSView *view = idFromObject(cx, obj);
	[view setHidden:!jsasbool(cx, argv[0])];
	return JSVAL_VOID;
}

jsvalue cocoaAlphaSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSView *view = idFromObject(cx, obj);
	double v = jsasnum(cx, argv[0]);
	if (gInAnimation)
		[[view animator] setAlphaValue:v];
	else
		[view setAlphaValue:v];
	return JSVAL_VOID;
}

jsvalue controlEnabledSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSControl *view = idFromObject(cx, obj);
	[view setEnabled:jsasbool(cx, argv[0])];
	return JSVAL_VOID;
}

jsvalue controlDataSourceSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	jsvalue me = OBJECT_TO_JSVAL(obj);
	if (JSVAL_IS_OBJECT(argv[0])) {
		jsvalue fn = jsget(cx, argv[0], 0, "bindControl");
		jsinvoke(cx, fn, argv[0], &me, 1);
	}
	return JSVAL_VOID;
}

jsvalue cocoaButtonTitleGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSButton *view = idFromObject(cx, obj);
	return jsstrFromNSString(cx, [view title]);
}

jsvalue cocoaButtonTitleSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSButton *view = idFromObject(cx, obj);
	NSString *title = jsasstrRetain(cx, argv[0]);
	[view setTitle:title];
	[title release];
	return JSVAL_VOID;
}

jsvalue cocoaTextFieldTextGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSTextField *view = idFromObject(cx, obj);
	return jsstrFromNSString(cx, [view stringValue]);
}

jsvalue cocoaTextFieldTextSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSTextField *view = idFromObject(cx, obj);
	NSString *title = jsasstrRetain(cx, argv[0]);	
	[view setStringValue:title];
	[title release];
	return JSVAL_VOID;
}

jsvalue progressMinimumGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSProgressIndicator *view = idFromObject(cx, obj);
	return jsnum(cx, [view minValue]);
}

jsvalue progressMinimumSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSProgressIndicator *view = idFromObject(cx, obj);
	
	[view setMinValue: jsasnum(cx, argv[0])];
	return JSVAL_VOID;
}

jsvalue progressMaximumGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSProgressIndicator *view = idFromObject(cx, obj);
	return jsnum(cx, [view maxValue]);
}

jsvalue progressMaximumSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSProgressIndicator *view = idFromObject(cx, obj);
	
	[view setMaxValue: jsasnum(cx, argv[0])];
	return JSVAL_VOID;
}

jsvalue progressValueGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSProgressIndicator *view = idFromObject(cx, obj);
	return jsnum(cx, [view doubleValue]);
}

jsvalue progressValueSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSProgressIndicator *view = idFromObject(cx, obj);
	
	double jd = jsasnum(cx, argv[0]);
	[view setDoubleValue: jd];
	return JSVAL_VOID;
}

jsvalue cocoaButtonStateGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSButton *view = idFromObject(cx, obj);
	
	return jsnumi(cx, [view state]);
}

jsvalue cocoaButtonStateSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSButton *view = idFromObject(cx, obj);
	
	[view setState:jsasint(cx, argv[0])];
	return JSVAL_VOID;
}

jsvalue cocoaButtonCheckedGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSButton *view = idFromObject(cx, obj);
	
	if ([view state])
		return JSVAL_TRUE;
	else
		return JSVAL_FALSE;
}

jsvalue cocoaButtonCheckedSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	NSButton *view = idFromObject(cx, obj);
		
	[view setState:jsasbool(cx, argv[0]) ? NSOnState : NSOffState];
	return JSVAL_VOID;
}

jsvalue cocoaViewMoveMethod(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSView *view = idFromObject(cx, obj);
	if (argc < 2)
		return JSVAL_TRUE;
	NSRect frame = [view frame];
	frame.origin.x = jsasnum(cx, args[0]);
	frame.origin.y = jsasnum(cx, args[1]);
	if (argc >= 4) {
		frame.size.width = jsasnum(cx, args[2]);
		frame.size.height = jsasnum(cx, args[3]);
	}
	if (gInAnimation)
		[[view animator] setFrame:frame];
	else
		[view setFrame:frame];
	return JSVAL_VOID;
}

jsvalue cocoaViewInvalidate(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSView *view = idFromObject(cx, obj);
	[view setNeedsDisplay: YES];
	return JSVAL_VOID;
}

jsvalue cocoaPopupClear(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSPopUpButton *view = idFromObject(cx, obj);
	[view removeAllItems];
	return JSVAL_VOID;
}

jsvalue cocoaPopupAdd(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSPopUpButton *view = idFromObject(cx, obj);
	NSMenu *m = [view menu];
	for (int idx = 0; idx < argc; idx++) {
		NSString *str = jsasstrRetain(cx, args[idx]);
		[m addItem:[[NSMenuItem alloc] initWithTitle:str action:nil keyEquivalent:@""]];
		[str release];
	}
	return JSVAL_VOID;
}

jsvalue cocoaBoxRadioValueGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSBox *box = idFromObject(cx, obj);
	NSView *container = [box contentView];

	NSArray *items = [container subviews];
	int count = [items count];
	for (int idx = 0; idx < count; idx++) {
		NSButton *other = [items objectAtIndex:idx];
		if ([other isKindOfClass:[NSRadioButtonICM class]]) {
			if ([other state]) {
				NSRadioButtonICM *radio = (NSRadioButtonICM *) other;
				if (radio->radio != nil) {
					return jsget(cx, radio->radio->val, 0, "value");
				}
				return JSVAL_VOID;
			}
		}
	}
	return JSVAL_VOID;
}

jsvalue cocoaBoxRadioValueSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSBox *box = idFromObject(cx, obj);
	NSView *container = [(id) box contentView];

	NSArray *items = [container subviews];
	int count = [items count];
	for (int idx = 0; idx < count; idx++) {
		NSButton *other = [items objectAtIndex:idx];
		if ([other isKindOfClass:[NSRadioButtonICM class]]) {
			NSRadioButtonICM *radio = (NSRadioButtonICM *) other;
			if (radio->radio != nil) {
				jsvalue radioVal = jsget(cx, radio->radio->val, 0, "value");
				if (jseq(cx, args[0], radioVal)) {
					[other setState: 1];
				} else {
					[other setState: 0];
				}
			}
		}
	}
	return JSVAL_VOID;
}

jsvalue cocoaPopupValueGetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSPopUpButton *box = idFromObject(cx, obj);
	return jsnumi(cx, [box indexOfSelectedItem]);
}

jsvalue cocoaPopupValueSetter(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSPopUpButton *box = idFromObject(cx, obj);

	[box selectItemAtIndex:jsasint(cx, args[0])];
	return JSVAL_VOID;
}

jsvalue webSetURL(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	if (argc < 1)
		return JSVAL_VOID;
	WebView *webView = idFromObject(cx, obj);
	NSString *url = jsasstrRetain(cx, args[0]);
	[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
	[url release];

	return JSVAL_VOID;
}

jsvalue webSetHTML(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	if (argc < 1)
		return JSVAL_VOID;
	WebView *webView = idFromObject(cx, obj);
	NSString *html = jsasstrRetain(cx, args[0]);
	[[webView mainFrame] loadHTMLString:html baseURL: [NSURL URLWithString:@"http://nil"]];
	[html release];
	return JSVAL_VOID;
}

jsvalue tableReload(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSTableView *tableView = idFromObject(cx, obj);

	[tableView reloadData];
	return JSVAL_VOID;
}

jsvalue browserReload(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *args, int argc) {
	NSBrowser *tableView = idFromObject(cx, obj);
	
	[tableView loadColumnZero];
	return JSVAL_VOID;
}

jsvalue viewConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	return JSVAL_VOID;
}

static void connectControl(jscontext *cx, NSView *btn, jsvalue obj, jsvalue form, jsvalue container, jsvalue defn) {
//	NSString *name = jsgetstring(cx, defn, 0, "name", @"nil");
	
//	jsset(cx, form, 0, keyFromString(name), obj);
//	jsset(cx, obj, 0, "form", form);
	idToObject(cx, obj, btn);
	
	bool lockLeft = jsgetbool(cx, defn, 0, "lockLeft", 0);
	bool lockRight = jsgetbool(cx, defn, 0, "lockRight", 0);
	bool lockTop = jsgetbool(cx, defn, 0, "lockTop", 0);
	bool lockBottom = jsgetbool(cx, defn, 0, "lockBottom", 0);
	
	int mask = 0;
	
	if (lockLeft && lockRight)
		mask = NSViewWidthSizable;
	else if (lockRight)
		mask = NSViewMinXMargin;
	else
		mask = NSViewMaxXMargin;

	if (lockTop && lockBottom)
		mask |= NSViewHeightSizable;
	else if (lockBottom)
		mask |= NSViewMinYMargin;
	else
		mask |= NSViewMaxYMargin;
	
	[btn setAutoresizingMask:mask];
	
	NSString *parentName = jsgetstring(cx, defn, 0, "parent", nil);
	if (parentName != nil) {
		jsvalue parentContainer = jsget(cx, form, 0, [parentName UTF8String]);
		if (parentContainer != nil)
			container = parentContainer;
	}
	
	id parent = idFromObject(cx, container);
	if ([parent isKindOfClass:[NSWindow class]])
		[[(NSWindow *) parent contentView] addSubview:btn];
	else if ([parent isKindOfClass:[NSView class]])
		[(NSView *) parent addSubview:btn];
}

jsvalue buttonConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
		
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
		
		NSButton *btn = [[NSButton alloc] initWithFrame:frame];
		[btn setButtonType:NSMomentaryPushInButton];
		[btn setBezelStyle:NSRoundedBezelStyle];
		
		[btn setTitle:jsgetstring(cx, defn, 0, "caption", @"")];
		
		[btn setEnabled: jsgetbool(cx, defn, 0, "enabled", 1)];
		
		int shortcut = jsgetint(cx, defn, 0, "shortcut", 0);
		if (shortcut == 1)
			[btn setKeyEquivalent:@"\r"];
		else if (shortcut == 2)
			[btn setKeyEquivalent:@"\e"];

		jsvalue clickHandler = jsget(cx, defn, 0, "Click");
		if (clickHandler)
		{
			jsset(cx, obj, 0, "Click", clickHandler);
			ActionBridge *bridge = [[ActionBridge alloc] initWithObject:obj withEvent:@"Click" withContext:cx withTarget:form];
			[btn setAction:@selector(doIt:)];
			[btn setTarget:bridge];
		}
		
		connectControl(cx, btn, obj, form, container, defn);
	}

	return JSVAL_VOID;
}

jsvalue checkBoxConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
		
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
		
		NSButton *btn = [[NSButton alloc] initWithFrame:frame];
		[btn setButtonType:NSSwitchButton];
		[btn setTitle:jsgetstring(cx, defn, 0, "caption", @"")];
		[btn setEnabled: jsgetbool(cx, defn, 0, "enabled", 1)];
		[btn setIntValue: jsgetbool(cx, defn, 0, "checked", 0)];

		jsvalue clickHandler = jsget(cx, defn, 0, "Click");
		if (clickHandler)
		{
			jsset(cx, obj, 0, "Click", clickHandler);
			ActionBridge *bridge = [[ActionBridge alloc] initWithObject:obj withEvent:@"Click" withContext:cx withTarget:form];
			[btn setAction:@selector(doIt:)];
			[btn setTarget:bridge];
		}
		
		connectControl(cx, btn, obj, form, container, defn);
	}
	
	return JSVAL_VOID;
}

jsvalue boxConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
		
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
		
		NSBox *btn = [[NSBox alloc] initWithFrame:frame];
		[btn setContentView:[FlippedView new]];
		[btn setTitle:jsgetstring(cx, defn, 0, "caption", @"")];
		
		connectControl(cx, btn, obj, form, container, defn);
	}
	
	return JSVAL_VOID;
}

jsvalue textConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		NSTextField *lbl;
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
		
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
		
		if (jsgetbool(cx, defn, 0, "password", false))
			lbl = [[NSSecureTextField alloc] initWithFrame:frame];
		else
			lbl = [[NSTextField alloc] initWithFrame:frame];
		
		
		[lbl setStringValue:jsgetstring(cx, defn, 0, "text", @"")];
		[lbl setEditable:jsgetbool(cx, defn, 0, "editable", false)];
		[lbl setSelectable:jsgetbool(cx, defn, 0, "selectable", false)];

		NSString *type = jsgetstring(cx, defn, 0, "type", @"");
		
		if ([type isEqualToString: @"label"]) {
			[lbl setBezeled:NO];
			[lbl setDrawsBackground:NO];
		} else {
			[[lbl cell] setWraps: NO];
			[[lbl cell] setScrollable: YES];
		}
		
		connectControl(cx, lbl, obj, form, container, defn);
	}		
	return JSVAL_VOID;
}

jsvalue canvasConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		CanvasView *canvas;
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
		
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
		
		jscopy(cx, obj, defn, 0, "Paint");
		
		canvas = [[CanvasView alloc] initWithFrame:frame];
		
		[canvas setObject: obj withTarget: form withContext: cx];

		connectControl(cx, canvas, obj, form, container, defn);
	}		
	return JSVAL_VOID;
}

jsvalue tableViewConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
				
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
		
		jscopy(cx, obj, defn, 0, "Paint");
		
		TableView *btn = [[TableView alloc] initWithFrame:frame];
		[btn setObject:obj withTarget: form withContext: cx];

		jscopy(cx, obj, defn, 0, "RowCount");
		jscopy(cx, obj, defn, 0, "Row");
		jscopy(cx, obj, defn, 0, "SelectionChanged");
		jscopy(cx, obj, defn, 0, "DoubleClick");
/*
		jsval jv = OBJECT_TO_JSVAL(obj);
		JS_SetProperty(cx, root, [name UTF8String], &jv);		
		JS_SetProperty(cx, obj, "form", &rootval);
		
		dataSourceName = [defn objectForKey:@"dataSource"];
		if (dataSourceName) {
			[dataSourceLoadMap setObject:dataSourceName forKey:name];
		}
		copyStringProperty(obj, defn, @"dataField");
		
		JS_RemoveRoot(cx, &obj);		
		
		[btn awakeFromDefn: defn];
		return btn;
		
		*/
		
		connectControl(cx, btn, obj, form, container, defn);
		[btn awakeFromDefn:defn];
	}
	return JSVAL_VOID;
}

jsvalue browserViewConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		BrowserView *ctl;
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
		
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
		
		jscopy(cx, obj, defn, 0, "RowCount");
		jscopy(cx, obj, defn, 0, "Row");
		
		ctl = [[BrowserView alloc] initWithFrame:frame];
		
		[ctl setObject: obj withTarget: form withContext: cx];
		
		connectControl(cx, ctl, obj, form, container, defn);
	}		
	return JSVAL_VOID;
}

jsvalue popupConstructor(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	if (argc >= 3) {
		NSPopUpButton *ctl;
		jsvalue form = argv[0];
		jsvalue container = argv[1];
		jsvalue defn = argv[2];
		NSRect frame;
		
		frame.origin.x = jsgetdouble(cx, defn, 0, "left", 0);
		frame.origin.y = jsgetdouble(cx, defn, 0, "top", 0);
		frame.size.width = jsgetdouble(cx, defn, 0, "width", 0);
		frame.size.height = jsgetdouble(cx, defn, 0, "height", 0);
				
		ctl = [[NSPopUpButton alloc] initWithFrame:frame];
				
		jscopy(cx, obj, defn, 0, "Click");

		
		ActionBridge *bridge = [[ActionBridge alloc] initWithObject:obj withEvent:@"Click" withContext:cx withTarget:form];
		[ctl setAction:@selector(doIt:)];
		[ctl setTarget:bridge];
		
		connectControl(cx, ctl, obj, form, container, defn);		
	}		
	return JSVAL_VOID;
}


jsvalue loadTableView(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	TableView *btn = idFromObject(cx, obj);
	[btn awake];
	return JSVAL_VOID;
}
jsvalue loadBrowserView(jscontext *cx, jsframe *outer, jsvalue obj, jsvalue *argv, int argc) {
	BrowserView *btn = idFromObject(cx, obj);
	[btn browserAwake];
	return JSVAL_VOID;
}

/*
JSClass cocoaViewClass = {"NSView", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaViewFinalizer 
};

JSClass cocoaButtonClass = {"NSButton", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaButtonFinalizer 
};

JSClass cocoaBoxClass = {"NSBox", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaBoxFinalizer 
};

JSClass cocoaTextFieldClass = {"NSTextField", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaButtonFinalizer 
};

JSClass cocoaProgressClass = {"NSProgress", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaButtonFinalizer 
};

JSClass cocoaPopupClass = {"NSPopup", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaPopupFinalizer 
};

JSClass cocoaWebClass = {"WebView", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaWebFinalizer 
};

JSClass cocoaTableClass = {"CocoalTable", JSCLASS_HAS_RESERVED_SLOTS(1), 
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub, 
JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,cocoaTableFinalizer 
};

JSPropertySpec cocoaViewProps[] = {
{"left", 0, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaViewFrameGetter, cocoaViewFrameSetter },
{"top", 1, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaViewFrameGetter, cocoaViewFrameSetter },
{"width", 2, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaViewFrameGetter, cocoaViewFrameSetter },
{"height", 3, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaViewFrameGetter, cocoaViewFrameSetter },
{"visible", 4, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaVisibleGetter, cocoaVisibleSetter },
{"alpha", 5, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaAlphaGetter, cocoaAlphaSetter },
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaViewFunctions[] = {
{"move", cocoaViewMoveMethod, 4, 0, 0 },
{"invalidate", cocoaViewInvalidate, 0, 0, 0 },
{0, 0, 0, 0, 0}
};

JSPropertySpec cocoaButtonProps[] = {
{"caption", 1, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaButtonTitleGetter, cocoaButtonTitleSetter },
{"state", 1, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaButtonStateGetter, cocoaButtonStateSetter },
{"checked", 1, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaButtonCheckedGetter, cocoaButtonCheckedSetter },
{"enabled", 5, JSPROP_ENUMERATE | JSPROP_SHARED, controlEnabledGetter, controlEnabledSetter },
{"dataSource", 2, JSPROP_ENUMERATE, nil, controlDataSourceSetter },
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaButtonFunctions[] = {
{0, 0, 0, 0, 0}
};

JSPropertySpec cocoaTextFieldProps[] = {
{"text", 1, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaTextFieldTextGetter, cocoaTextFieldTextSetter },
{"dataSource", 2, JSPROP_ENUMERATE, nil, controlDataSourceSetter },
{"enabled", 5, JSPROP_ENUMERATE | JSPROP_SHARED, controlEnabledGetter, controlEnabledSetter },
{0, 0, 0, 0, 0}
};

JSPropertySpec cocoaBoxProps[] = {
{"radioValue", 1, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaBoxRadioValueGetter, cocoaBoxRadioValueSetter },
{"dataSource", 2, JSPROP_ENUMERATE, nil, controlDataSourceSetter },
{0, 0, 0, 0, 0}
};

JSPropertySpec cocoaPopupProps[] = {
{"value", 1, JSPROP_ENUMERATE | JSPROP_SHARED, cocoaPopupValueGetter, cocoaPopupValueSetter },
{"enabled", 5, JSPROP_ENUMERATE | JSPROP_SHARED, controlEnabledGetter, controlEnabledSetter },
{0, 0, 0, 0, 0}
};

JSPropertySpec cocoaProgressProps[] = {
{"minimum", 0, JSPROP_ENUMERATE | JSPROP_SHARED, progressMinimumGetter, progressMinimumSetter },
{"maximum", 1, JSPROP_ENUMERATE | JSPROP_SHARED, progressMaximumGetter, progressMaximumSetter },
{"value", 2, JSPROP_ENUMERATE | JSPROP_SHARED, progressValueGetter, progressValueSetter },
{0, 0, 0, 0, 0}
};

JSPropertySpec cocoaWebProps[] = {
{0, 0, 0, 0, 0}
};

JSPropertySpec cocoaTableProps[] = {
{"dataSource", 2, JSPROP_ENUMERATE, nil, controlDataSourceSetter },
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaTextFieldFunctions[] = {
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaBoxFunctions[] = {
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaTableFunctions[] = {
{"reload", tableReload, 1, 0, 0 },
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaWebFunctions[] = {
{"setURL", webSetURL, 1, 0, 0 },
{"setHTML", webSetHTML, 1, 0, 0 },
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaPopupFunctions[] = {
{"clear", cocoaPopupClear, 0, 0, 0 },
{"add", cocoaPopupAdd, 1, 0, 0 },
{0, 0, 0, 0, 0}
};

JSFunctionSpec cocoaProgressFunctions[] = {
{0, 0, 0, 0, 0}
};

jsobject *cocoaViewObject;
jsobject *cocoaButtonObject;
jsobject *cocoaBoxObject;
jsobject *cocoaTextFieldObject;
jsobject *cocoaProgressObject;
jsobject *cocoaPopupObject;
jsobject *cocoaWebObject;
jsobject *cocoaTableObject;

void registerControls(jscontext *cx, jsobject *global) {
	JS_AddRoot(cx, &cocoaViewObject);
	JS_AddRoot(cx, &cocoaButtonObject);
	JS_AddRoot(cx, &cocoaBoxObject);
	JS_AddRoot(cx, &cocoaTextFieldObject);
	JS_AddRoot(cx, &cocoaProgressObject);
	JS_AddRoot(cx, &cocoaPopupObject);
	JS_AddRoot(cx, &cocoaWebObject);
	JS_AddRoot(cx, &cocoaTableObject);

	cocoaViewObject = JS_InitClass(cx, global, NULL, &cocoaViewClass,
				 cocoaViewConstructor, 0,
				 cocoaViewProps,
				 cocoaViewFunctions, 
				 NULL, NULL);
	cocoaButtonObject = JS_InitClass(cx, global, cocoaViewObject, &cocoaButtonClass,
				 cocoaButtonConstructor, 0,
				 cocoaButtonProps,
				 cocoaButtonFunctions, 
				 NULL, NULL);
	cocoaBoxObject = JS_InitClass(cx, global, cocoaViewObject, &cocoaBoxClass,
									 cocoaBoxConstructor, 0,
									 cocoaBoxProps,
									 cocoaBoxFunctions, 
									 NULL, NULL);
	cocoaTextFieldObject = JS_InitClass(cx, global, cocoaViewObject, &cocoaTextFieldClass,
				 cocoaButtonConstructor, 0,
				 cocoaTextFieldProps,
				 cocoaTextFieldFunctions, 
				 NULL, NULL);
	cocoaProgressObject = JS_InitClass(cx, global, cocoaViewObject, &cocoaProgressClass,
										cocoaButtonConstructor, 0,
										cocoaProgressProps,
										cocoaProgressFunctions, 
										NULL, NULL);
	cocoaPopupObject = JS_InitClass(cx, global, cocoaViewObject, &cocoaPopupClass,
									   cocoaPopupConstructor, 0,
									   cocoaPopupProps,
									   cocoaPopupFunctions, 
									   NULL, NULL);
	cocoaWebObject = JS_InitClass(cx, global, cocoaViewObject, &cocoaWebClass,
									cocoaWebConstructor, 0,
									cocoaWebProps,
									cocoaWebFunctions, 
									NULL, NULL);
	cocoaTableObject = JS_InitClass(cx, global, cocoaViewObject, &cocoaTableClass,
								  cocoaTableConstructor, 0,
								  cocoaTableProps,
								  cocoaTableFunctions, 
								  NULL, NULL);
}
*/

void registerControls(jscontext *cx) {
	jsvalue view, button, text, canvas, popup, tableView, checkbox, box, outlineView, browserView;
	
	jsvalue UI = cx->slots[9];
	
	// set up class framework
	jsset(cx, UI, 0, "CoreView", view = bindFunction(cx, viewConstructor));
	jsset(cx, UI, 0, "ButtonControl", button = jsclass(cx, buttonConstructor, view));
	jsset(cx, UI, 0, "TextControl", text = jsclass(cx, textConstructor, view));
	jsset(cx, UI, 0, "CanvasControl", canvas = jsclass(cx, canvasConstructor, view));
	jsset(cx, UI, 0, "PopupControl", popup = jsclass(cx, popupConstructor, view));
	jsset(cx, UI, 0, "TableView", tableView = jsclass(cx, tableViewConstructor, view));
	jsset(cx, UI, 0, "OutlineView", outlineView = jsclass(cx, tableViewConstructor, view));
	jsset(cx, UI, 0, "BrowserView", browserView = jsclass(cx, browserViewConstructor, view));
	jsset(cx, UI, 0, "CheckBox", checkbox = jsclass(cx, checkBoxConstructor, view));
	jsset(cx, UI, 0, "BoxControl", box = jsclass(cx, boxConstructor, view));
	
	// set up methods
	jsadddynamicfield(cx, view, 0, "left", cocoaLeftGetter, cocoaLeftSetter);
	jsadddynamicfield(cx, view, 0, "top", cocoaTopGetter, cocoaTopSetter);
	jsadddynamicfield(cx, view, 0, "width", cocoaWidthGetter, cocoaWidthSetter);
	jsadddynamicfield(cx, view, 0, "height", cocoaHeightGetter, cocoaHeightSetter);
	jsaddfield(cx, view, 0, "invalidate", bindFunction(cx, cocoaViewInvalidate));

	jsadddynamicfield(cx, text, 0, "text", cocoaTextFieldTextGetter, cocoaTextFieldTextSetter);

	jsaddfield(cx, tableView, 0, "_load", bindFunction(cx, loadTableView));
	jsaddfield(cx, tableView, 0, "reload", bindFunction(cx, tableReload));

	
	jsaddfield(cx, outlineView, 0, "_load", bindFunction(cx, loadTableView));
	jsaddfield(cx, browserView, 0, "_load", bindFunction(cx, loadBrowserView));
	jsaddfield(cx, browserView, 0, "reload", bindFunction(cx, browserReload));

	jsaddfield(cx, popup, 0, "clear", bindFunction(cx, cocoaPopupClear));
	jsaddfield(cx, popup, 0, "add", bindFunction(cx, cocoaPopupAdd));
	jsadddynamicfield(cx, popup, 0, "value", cocoaPopupValueGetter, cocoaPopupValueSetter);

}
